package com.fingard.dsp.bank.directbank.lu11;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import com.fingard.constant.DateFormat2;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.ReqBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.ReqQryBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.RetAtsBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.RetAtsQryBatRecRefund;
import com.fingard.dsp.bank.reqrespobj.batrecrefund.detail.RetAtsBatRecRefundDetail;
import com.fingard.io.FileHelper;
import com.fingard.net.ConnState;
import com.fingard.net.FtpReceiver;
import com.fingard.net.SftpPortClient;
import com.fingard.text.StringHelper;
import com.fingard.util.ZipHelper;

/**
 * 陆金所退保接口
 * 
 * 参考文档：陆金所保险系统外部对接文档_B模式_20161101.docx
 * 
 * @author fanghh
 * @version 1.0
 * @lastModified 2018/5/14
 */
public class LU11BatRecRefund extends LU11Base implements IBatRecRefund {
	/**
	 * 退保提交
	 * 
	 * 参考接口：1.7 退保结果文件
	 * 
	 * 文件名命名规则
	 * ${instid}_refundResult_yyyyMMdd_{1}.zip
	 * ${instid}_refundResult_yyyyMMdd_{1}.csv
	 */
	@Override
	public RetAtsBatRecRefund submitBatRecRefund(ReqBatRecRefund p_reqBatRef) throws Exception {
		RetAtsBatRecRefund retAts = new RetAtsBatRecRefund(p_reqBatRef.reqHeader);

		SftpPortClient sftpPortClient = null;
		
		try {
			// 退保文件内容
			StringBuilder sbFileContent = new StringBuilder();
			
			// 流水映射文件内容
			StringBuilder seqNoMappingContent = new StringBuilder();
			while (p_reqBatRef.readRecord()) {
				if (seqNoMappingContent.length() > 0) {
					seqNoMappingContent.append("\r\n");
				}
				if (sbFileContent.length() > 0) {
					sbFileContent.append("\r\n");
				}
				
				String orderId = p_reqBatRef.readedDetail.oriOppOrderNo;
				String refundId = p_reqBatRef.readedDetail.refundNo;
				String proposalNo = p_reqBatRef.readedDetail.proposalNo;
				String productId = p_reqBatRef.readedDetail.productId;
				String refundFlag = p_reqBatRef.readedDetail.refundFlag;
				String refundType = p_reqBatRef.readedDetail.refundType;
				String payAmt = p_reqBatRef.readedDetail.payAmount;
				String applyAmt = p_reqBatRef.readedDetail.applyAmt;
				String profit = p_reqBatRef.readedDetail.profit;
				String fee = p_reqBatRef.readedDetail.fee;
				String confirmTime = new DateFormat2("yyyyMMdd HH:mm:ss").format(p_reqBatRef.readedDetail.getPayDateTime());
				String refundDesc = p_reqBatRef.readedDetail.refundDesc;
				String remainValue = p_reqBatRef.readedDetail.remainValue;
				String refundShare = p_reqBatRef.readedDetail.refundShare;
				
				String tmpReqBodyDetail = MessageFormat.format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\",\"{9}\",\"{10}\",\"{11}\",\"{12}\",\"{13}\"", 
						orderId, refundId, proposalNo, productId, refundFlag, refundType, payAmt, applyAmt, profit, fee, confirmTime, refundDesc, remainValue, refundShare);
				sbFileContent.append(tmpReqBodyDetail);
				
				seqNoMappingContent.append(p_reqBatRef.readedDetail.askNumber).append(",").append(refundId);
			}
			sbFileContent.append("\r\n");
			WriteBankLogLn2("本地退保文件内容:\r\n" + sbFileContent.toString());
			
			// 生成待上传文件并写入内容
			String refundFileDir = getRefundFileDirectory();
			Date tmpDateNow = new Date();
			
			String tmpBatSeqNo = String.valueOf(getBatSeqNo(refundFileDir));
			String refundFileName = bankFront.org + "_refundResult_" + Format.Date8Format.format(tmpDateNow) + "_" + tmpBatSeqNo;
			String localRefundFilePath = refundFileDir + File.separator + refundFileName + ".csv";
			WriteBankLogLn2("本地退保文件路径: " + localRefundFilePath);
			FileHelper.writeFile(localRefundFilePath, sbFileContent.toString(), getCharset());
			
			// 退保流水映射存入本地
			WriteBankLogLn2("本地退保流水映射文件内容:\r\n" + seqNoMappingContent.toString());
			String refundSeqNoPath = getDataFileDirectory(tmpDateNow) + File.separator + p_reqBatRef.reqBatchNO + "_" + tmpBatSeqNo + ".txt";
			WriteBankLogLn2("本地退保流水映射文件路径:" + refundSeqNoPath);
			FileHelper.writeFile(refundSeqNoPath, seqNoMappingContent.toString(), getCharset());
			
			// 压缩文件
			String localRefundZipFilePath = refundFileDir + File.separator + refundFileName + ".zip";
			WriteBankLogLn2("本地退保文件压缩包路径: " + localRefundZipFilePath);
			FileOutputStream fos = new FileOutputStream(new File(localRefundZipFilePath));
			ZipHelper.toZip(localRefundFilePath, fos, true);

			// 上传退保文件
			FtpSet ftpSet = bankFront.getFtpSet("refund_upload");
			sftpPortClient = new SftpPortClient(ftpSet);
			String  directDir = "";
			String tmpDate = Format.Date8Format.format(tmpDateNow);
			if (ftpSet.upDir.endsWith("/")) {
				directDir = tmpDate;
			} else {
				directDir = "/" + tmpDate;
			}
			String sftpFilePath = StringHelper.trimEnd(ftpSet.upDir, "/") + "/" + tmpDate + "/" + refundFileName + ".zip";
			WriteBankLogLn2("SFTP服务器压缩文件上传路径:" + sftpFilePath);
			FtpReceiver ftpReceiver = sftpPortClient.uploadFile(directDir, localRefundZipFilePath, sftpFilePath);
			if(StringHelper.hasAnyChar(ftpReceiver.connMsg)){
				this.WriteBankLogLn("上传返回消息：" + ftpReceiver.connMsg);
			}
			
			retAts.respCode = "0";
			retAts.reqSeqID = p_reqBatRef.reqBatchNO;
			if (ftpReceiver.isCompleted) {
				retAts.respInfo = "上传成功";
				retAts.transState = "Uploaded";
				retAts.payInfoCode = "I4001";
			} else if (ConnState.FAIL.equals(ftpReceiver.connState)) {
				retAts.respInfo = "上传通讯失败";
				retAts.transState = "BatchFailed";
				retAts.payInfoCode = "E9999";
			} else {
				retAts.respCode = "-1";
				retAts.respInfo = ftpReceiver.connMsg;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.toString();
			WriteBankLogLn(ex);
		} finally{
    		if(sftpPortClient != null){
    			try {
					sftpPortClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
					WriteBankLogLn(e);
				}
    		}
    	}

		if ("-1".equals(retAts.respCode) && StringHelper.isNullOrEmpty(retAts.reqSeqID)) {
			retAts.reqSeqID = p_reqBatRef.reqBatchNO;
		}
		
		retAts.writeRetToATS();
		return retAts;
	}

	/**
	 * 退保查询
	 * 
	 * 参考接口：1.8 退保资金划拨结果文件
	 * 
	 * 文件名命名规则
	 * {instid}_refundFunds_yyyyMMdd_(1).csv,
	 * {instid}_refundFunds_yyyyMMdd_(1).zip
	 */
	@Override
	public RetAtsQryBatRecRefund queryBatRecRefund(ReqQryBatRecRefund p_reqQryBatRef) throws Exception {
		RetAtsQryBatRecRefund retAts = new RetAtsQryBatRecRefund(p_reqQryBatRef.reqHeader);
		retAts.reqSeqID = p_reqQryBatRef.reqBatchNO;
		
		SftpPortClient sftpPortClient = null;
		
		try {
			File refundSeqNoDir = new File(getDataFileDirectory(p_reqQryBatRef.getBgnDateTime()));
			if (refundSeqNoDir.exists()) {
				File[] refundSeqNoFileList = refundSeqNoDir.listFiles();
				boolean isMatched = false;
				for(File refundSeqNoFile : refundSeqNoFileList) {
					if (refundSeqNoFile.getName().contains(p_reqQryBatRef.reqBatchNO)) {
						isMatched = true;
						// 1、读取本地退保流水映射文件
						String tmpSeqNoContent = FileHelper.readFileText(refundSeqNoFile.getPath(), getCharset());
						WriteBankLogLn2("本地退保流水映射文件内容:\r\n" + tmpSeqNoContent);
						if (StringHelper.isNullOrEmpty(tmpSeqNoContent)) {
							retAts.respCode = "-1";
			    			retAts.respInfo = "退保流水映射文件内容为空!";
			    			retAts.writeAfterDetail();
			    			return retAts;
						}
						String[] tmpSeqNoArray = tmpSeqNoContent.split("\r\n");
						
						FtpSet ftpSet = bankFront.getFtpSet("refund_download");
			            String directDir = "";
						String tmpDate = Format.Date8Format.format(p_reqQryBatRef.getBgnDateTime());
						if (ftpSet.downDir.endsWith("/")) {
							directDir = tmpDate;
						} else {
							directDir = "/" + tmpDate;
						}
						sftpPortClient = new SftpPortClient(ftpSet);
						
						// 2、读取本地标记文件
						String localTagContent = "";
						File localTagFile = new File(getTempFileDirectory() + File.separator + tmpDate + ".txt");
						if (localTagFile.exists()) {
							localTagContent = FileHelper.readToString(localTagFile, getCharset());
						}
						
						// 3、查找SFTP下载目录指定文件
						String qryBatRefundFileName = "";
						FtpReceiver ftpListFileReceiver = sftpPortClient.listFiles(ftpSet.downDir + directDir);
						if (!ftpListFileReceiver.isCompleted) {
							retAts.respCode = "-1";
							if (ConnState.FILE_NOT_EXISTS.equals(ftpListFileReceiver.connState)) {
				    			retAts.respInfo = "SFTP服务器批次结果文件尚未生成!";
							} else {
					    		retAts.respInfo = "遍历目录:" + ftpSet.downDir + directDir + "失败!";
							}
				    		retAts.writeAfterDetail();
							return retAts;
						}
						
						List<String> fileNameList = Arrays.asList(ftpListFileReceiver.connMsg.split(","));
						Iterator<String> it = fileNameList.iterator();
						while (it.hasNext()) {
							String sftpFileName = ((String)it.next()).toString();
							if (localTagFile.exists()) {
								// 本地标记文件存在，先遍历获取未处理的文件名(只有一个)
								if (localTagContent.contains(sftpFileName)) {
									continue;
								}
								qryBatRefundFileName = sftpFileName;
							} else {
								// 本地标记文件不存在，读取第一个文件名下载解析即可(只有一个)
								qryBatRefundFileName = sftpFileName;
							}
						}
						
						if (StringHelper.isNullOrEmpty(qryBatRefundFileName)) {
							retAts.respCode = "-1";
							retAts.respInfo = "服务器结果文件均已处理过，无需再次处理!";
				    		retAts.writeAfterDetail();
							return retAts;
						}
						
						// 4、下载退保结果文件至本地
						String localFilePath = createTempFileDirectory() + File.separator + qryBatRefundFileName;
			            WriteBankLogLn2("退保结果文件保存本地路径:" + localFilePath);
			            
						String sftpFilePath = ftpSet.downDir + directDir + "/" + qryBatRefundFileName;
						WriteBankLogLn2("待下载SFTP服务器压缩文件目录路径:" + sftpFilePath);
			            FtpReceiver ftpReceiver = sftpPortClient.downloadFile(directDir, qryBatRefundFileName, localFilePath);
			            if(StringHelper.hasAnyChar(ftpReceiver.connMsg)) {
							this.WriteBankLogLn("下载返回消息：" + ftpReceiver.connMsg);
						}
			            
			            if (ftpReceiver.isCompleted) {
			            	// 5、解压文件
			            	WriteBankLogLn("文件下载已完成，开始解压...");
			            	String tmpLocalDir = getTempFileDirectory();
                            ZipHelper.unzipFile(localFilePath, tmpLocalDir);
                            WriteBankLogLn("文件解压至已完成.");
                            
                            qryBatRefundFileName = qryBatRefundFileName.replace(".zip", "");
                            tmpLocalDir += File.separator + qryBatRefundFileName;
                            File depressDir = new File(tmpLocalDir);
                            if(depressDir.exists()) {
                            	String tmpStrRet = FileHelper.readFileText(tmpLocalDir  + File.separator + qryBatRefundFileName + ".csv", getCharset());
                            	WriteBankLogLn2("解压后文件内容:\r\n" + tmpStrRet);
                            	
                            	// 6、解析返回ATS
                            	if (StringHelper.hasAnyChar(tmpStrRet)) {
                            		retAts.respCode = "0";
        							retAts.reqSeqID = p_reqQryBatRef.reqBatchNO;
        							
        							StringReader strReader = new StringReader(tmpStrRet);
        							BufferedReader tmpReader = new BufferedReader(strReader);
        							
        							while(true) {
        								String eachline = tmpReader.readLine();
        								if(eachline == null){
        									break;
        								}
        								if (eachline.indexOf(",") > 0) {
        									String[] detailNodes = eachline.split(",");
        									RetAtsBatRecRefundDetail tmpRetDetail = new RetAtsBatRecRefundDetail();
        									
        									for(String tmpSeqNo : tmpSeqNoArray) {
        										if ((tmpSeqNo.length() > 0) && tmpSeqNo.contains(detailNodes[1].replace("\"", ""))) {
        											tmpRetDetail.askNumber = tmpSeqNo.split(",")[0];
        											tmpRetDetail.oriOppOrderNo = detailNodes[0].replace("\"", "");
        	    									tmpRetDetail.refundNo = detailNodes[1].replace("\"", "");
        	    									tmpRetDetail.payAmount = detailNodes[5].replace("\"", "");
        	    									
        	    									// 0：失败 1：成功
        	    									String transState = detailNodes[10].replace("\"", "");
        	    									if ("0".equals(transState)) {
        	    										tmpRetDetail.result = PaymentState.SUCCESS;
        	    									} else if ("1".equals(transState)) {
        	    										tmpRetDetail.result = PaymentState.FAIL_Payment;
        	    									} else if ("2".equals(transState)) {
        	    										tmpRetDetail.result = PaymentState.PAYING;
        	    									} else {
        	    										tmpRetDetail.result = PaymentState.EXCEPTION;
        	    									}
        	    									
        	    									tmpRetDetail.payInfoCode = detailNodes[11].replace("\"", "");
        	    									
        	        					        	retAts.writeRetDetail(tmpRetDetail);
        										}
        									}
        								}
        							}
        							
        							// 解析处理完毕后，在本地标记文件中写入已处理过文件
        							FileHelper.appendFile(localTagFile.getPath(), qryBatRefundFileName + "\r\n", getCharset());
                            	} else {
                            		retAts.respCode = "-1";
                            		retAts.respInfo = "解压后退保结果文件内容为空";
                            	}
                            } else {
                            	retAts.respCode = "-1";
                            	retAts.respInfo = "解压后目录[" + tmpLocalDir + "]不存在";
                            }
			            } else {
			            	retAts.respCode = "-1";
			    			retAts.respInfo = "退保结果文件下载失败:" + ftpReceiver.connMsg;
			            }
					} 
				}
				
				if (!isMatched) {
					retAts.respCode = "-1";
					retAts.respInfo = "本地退保流水映射目录不存在批次:" + p_reqQryBatRef.reqBatchNO + "流水映射文件!";
				}
			} else {
				retAts.respCode = "-1";
				retAts.respInfo = "本地退保流水映射目录不存在，未发生过退保交易!";
			}
		} catch(Exception ex) {
			ex.printStackTrace();
			retAts.respCode = "-1";
			retAts.respInfo = ex.getMessage();
			WriteBankLogLn(ex);
		} finally{
    		if(sftpPortClient != null){
    			try {
					sftpPortClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
					WriteBankLogLn(e);
				}
    		}
    	}
		
		retAts.writeAfterDetail();
		return retAts;
	}
}
